package com.ruoyi.api.v1;

import com.alibaba.fastjson.JSON;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.WxPayKit;
import com.ruoyi.cinema.BO.*;
import com.ruoyi.cinema.DTO.*;
import com.ruoyi.cinema.domain.Cinema;
import com.ruoyi.cinema.domain.Customer;
import com.ruoyi.cinema.domain.FilmSchedule;
import com.ruoyi.order.domain.*;
import com.ruoyi.cinema.event.GoodsBuyEvent;
import com.ruoyi.cinema.mapper.FilmScheduleMapper;
import com.ruoyi.cinema.service.*;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.WechatConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.constant.OrderConstant;
import com.ruoyi.order.DTO.ConfirmGoodsOrderYzDTO;
import com.ruoyi.order.DTO.ConfirmRechargeOrderYzDTO;
import com.ruoyi.order.DTO.ConfirmTicketOrderYzDTO;
import com.ruoyi.order.VO.OrderVO;
import com.ruoyi.order.mapper.MemberCardOrderMapper;
import com.ruoyi.order.mapper.OrderMapper;
import com.ruoyi.order.service.*;
import com.ruoyi.utils.YzResult;
import com.ruoyi.utils.YzUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

@RestController("v1_Order")
@RequestMapping(value = "api/v1/order")
public class OrderController  extends BaseController {

    @Autowired
    private IOrderService orderService;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private ICustomerService customerService;
    @Autowired
    private IFilmScheduleService filmScheduleService;
    @Autowired
    private IOrderTicketService orderTicketService;
    @Autowired
    private IOrderPromotionService orderPromotionService;
    @Autowired
    private IOrderPaymentService orderPaymentService;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private FilmScheduleMapper filmScheduleMapper;
    @Autowired
    private ICinemaService cinemaService;
    @Autowired
    private IMemberCardOrderService memberCardOrderService;
    @Autowired
    private MemberCardOrderMapper memberCardOrderMapper;
    @Autowired
    private IOrderGoodsService orderGoodsService;
    @Autowired
    private IOrderGoodsComboService orderGoodsComboService;
    @Autowired
    private IOrderFulfillInfoService orderFulfillInfoService;

    @Autowired
    private ApplicationContext applicationContext;


    @RepeatSubmit
    @PostMapping("/prePay")
    public AjaxResult prePay(@RequestBody OrderBO orderBO, HttpServletRequest request){

        if(null == orderBO.getCustomerId()){
            return AjaxResult.error(-1,"customerId 不能为空");
        }
        Customer customer = customerService.selectCustomerById(orderBO.getCustomerId());
        if(null == customer){
            return AjaxResult.error(-1,"找不到对应的用户");
        }
        String accessToken = customerService.getAccessToken(customer.getId(),customer.getPhone());
        if(StringUtils.isEmpty(accessToken)){
            return AjaxResult.error(-1,"获取accessToken失败，请绑定手机号后重试");
        }
        customer.setAccessToken(accessToken);
        if(StringUtils.isEmpty(orderBO.getPayMethodId())){
            return AjaxResult.error(-1, "payMethodId 不能为空");
        }
        if(StringUtils.isEmpty(orderBO.getLockOrderId())){
            return AjaxResult.error(-1,"lockOrderId 必传");
        }
        LockSeatBO ls = redisCache.getCacheObject(orderBO.getLockOrderId()+Constants.LOCK_SEAT_KEY);
        if(null == ls){
            return AjaxResult.error(-1,"未找到对应的锁坐信息");
        }
        PayTypeBo realPayType = null;
        CanUsePriceBO realUsedPrice = null;
        List<CanUsePriceBO> canUsePriceBOList = ls.getCanUsePriceBOList();
        for (CanUsePriceBO cpb :canUsePriceBOList) {
            List<PayTypeBo> payTypeBoList = cpb.getPayTypeList();
            for (PayTypeBo ptb :payTypeBoList) {
                if(ptb.getPayMethodId().equals(orderBO.getPayMethodId())){
                    realPayType = ptb;
                    realUsedPrice = cpb;
                }
            }
        }
        if(null == realPayType){
            return AjaxResult.error(-1,"为找到对应的支付方式");
        }
        if(!realUsedPrice.isCanUse()){
            return AjaxResult.error(-1,"当前优惠不可用");
        }

        Long leftSecond = redisCache.getCacheObjectExpire(orderBO.getLockOrderId()+Constants.LOCK_SEAT_KEY);
        if(realPayType.getPayMethodCode().equals(OrderConstant.WEIXIN)){
            if(leftSecond < 90){
                return AjaxResult.error(-1,"微信支付必须距离座位失效90秒以上");
            }
        }
        if(realPayType.getPayMethodCode().equals(OrderConstant.MEMBER_CARD)){
            if(leftSecond < 30){
                return AjaxResult.error(-1,"会员卡支付必须距离座位失效30秒以上");
            }
        }

        FilmSchedule fs = filmScheduleService.selectFilmScheduleById(ls.getId());
        if(null == fs){
            return AjaxResult.error(-1,"找不到对应的排期");
        }

        String openId = customer.getOpenId();
        String outId = IdUtils.fastSimpleUUID();

        Order order = new Order();
        order.setMobile(customer.getPhone());
        order.setCustomerId(customer.getId());
        order.setCinemaId(fs.getCinemaId());
        order.setFilmCode(fs.getFilmCode());
        order.setScheduleId(fs.getScheduleId());
        order.setScheduleKey(fs.getScheduleKey());
        order.setLockOrderId(orderBO.getLockOrderId());
        order.setOutId(outId);
        // todo 从canUsePrice中取
        order.setType(OrderConstant.ORDER_TYPE_TICKET);
        order.setStatus(OrderConstant.ORDER_STATUS_WAIT_PAY);
        //todo 后面分解出来
        order.setGoodsPayAmount(realUsedPrice.getGoodsPayAmount());
        order.setTicketPayAmount(realUsedPrice.getOrderPayAmount());
        order.setOrderAmount(realUsedPrice.getOrderAmount());
        order.setPayAmount(realUsedPrice.getPayAmount());
        order.setPromoAmount(realUsedPrice.getPromoAmount());

        orderService.insertOrder(order);
        List<OrderTicket> orderTicketList = new ArrayList<>(realUsedPrice.getTicketList().size());
        for (OrderTicketBO otb :realUsedPrice.getTicketList()) {
            OrderTicket ot = new OrderTicket();
            ot.setActivityCode(otb.getActivityCode());
            ot.setSeatCode(otb.getSeatCode());
            ot.setOrderId(order.getId());
            orderTicketService.insertOrderTicket(ot);
            orderTicketList.add(ot);
        }
        order.setOrderTicketList(orderTicketList);

        if(null != realUsedPrice.getPromotionList()){
            List<OrderPromotion> orderPromotionList = new ArrayList<>(realUsedPrice.getPromotionList().size());
            for (OrderPromotion op :realUsedPrice.getPromotionList()) {
                OrderPromotion orderPromotion = new OrderPromotion();
                orderPromotion.setOrderId(order.getId());
                orderPromotion.setPromoAmount(op.getPromoAmount());
                orderPromotion.setPromoCode(op.getPromoCode());
                orderPromotion.setPromoType(op.getPromoType());
                orderPromotionService.insertOrderPromotion(orderPromotion);
                orderPromotionList.add(orderPromotion);
            }
            order.setOrderPromotionList(orderPromotionList);
        }

        List<OrderPayment> orderPaymentList = new ArrayList<>(2);
        OrderPayment orderPayment = new OrderPayment();
        orderPayment.setOrderId(order.getId());
        orderPayment.setPayAmount(realPayType.getPayAmount());
        orderPayment.setPayCode(realPayType.getPayCode());
        if(realPayType.getPayMethodCode().equals(OrderConstant.WEIXIN)){
            orderPayment.setPayCode(IdUtils.fastSimpleUUID());
        }
        orderPayment.setPayMethodCode(realPayType.getPayMethodCode());
        if(orderPayment.getPayAmount() > 0){
            orderPaymentService.insertOrderPayment(orderPayment);
            orderPaymentList.add(orderPayment);
        }

        PayTypeBo couponPay = realUsedPrice.getCouponPay();
        OrderPayment couponOrderPay = null;
        if(null != couponPay){
             couponOrderPay = new OrderPayment();
            couponOrderPay.setOrderId(order.getId());
            couponOrderPay.setPayAmount(couponPay.getPayAmount());
            couponOrderPay.setPayCode(couponPay.getPayCode());
            couponOrderPay.setPayMethodCode(couponPay.getPayMethodCode());
            couponOrderPay.setPayApply(couponPay.getPayApply());
            orderPaymentService.insertOrderPayment(couponOrderPay);
            orderPaymentList.add(couponOrderPay);
        }
        order.setOrderPaymentList(orderPaymentList);


        if(orderPayment.getPayMethodCode().equals(OrderConstant.WEIXIN) && (orderPayment.getPayAmount() > 0) ){
            return orderService.wechatPrePay(order.getId(),orderPayment.getPayAmount(), openId, orderPayment.getPayCode(),request,leftSecond - 30,"中视电影购票");
        }else if(orderPayment.getPayMethodCode().equals(OrderConstant.MEMBER_CARD)){
            return orderService.memberPay(order,customer);
        }else if(couponOrderPay != null){
            return orderService.memberPay(order,customer);
        }else{
            return AjaxResult.error(-1,"不支持的支付方式");
        }


    }



    @RequestMapping(value = "/wechatNotify", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String wechatNotify(HttpServletRequest request) {
        String xmlMsg = HttpKit.readData(request);
        logger.info("影片订单 支付通知=" + xmlMsg);
        Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);

        String returnCode = params.get("return_code");

        // 注意重复通知的情况，同一订单号可能收到多次通知，请注意一定先判断订单状态
        // 注意此处签名方式需与统一下单的签名类型一致
        if (WxPayKit.verifyNotify(params, WechatConstants.WECHAT_KEY, SignType.HMACSHA256)) {
            if (WxPayKit.codeIsOk(returnCode)) {
                // 更新订单信息
                // 发送通知等
                String out_trade_no = params.get("out_trade_no");
                List<OrderPayment> opl = orderPaymentService.selectByPayCode(out_trade_no);
                if(null == opl || opl.isEmpty()){
                    logger.error("------找不到对应的微信支付--------");
                    return null;
                }
                if(opl.size() > 1){
                    logger.info("-----找到多个code 对应的支付------");
                }
                Order o = new Order();
                o.setId(opl.get(0).getOrderId());
                List<Order> orderList = orderMapper.selectOrderAllList(o);
                if(null == orderList || orderList.isEmpty()){
                    logger.error("------找不到订单--------");
                    return null;
                }
                if(orderList.size()> 1){
                    logger.error("-----找到了多个订单-------");
                }
                Order order = orderList.get(0);
                if(order.getStatus().equals(OrderConstant.ORDER_STATUS_WAIT_PAY)){
                    order.setStatus(OrderConstant.ORDER_STATUS_PAY_SUCCESS);
                    int i =  orderMapper.updateOptimisticLock(order);
                    if(i == 1){
                        ConfirmTicketOrderYzDTO confirmTicketOrderYzDTO = new ConfirmTicketOrderYzDTO();
                        Customer customer =  customerService.selectCustomerById(order.getCustomerId());
                        FilmSchedule fs = filmScheduleMapper.selectFilmScheduleByScheduleId(order.getScheduleId());
                        String accessToken = customerService.getAccessToken(customer.getId(),customer.getPhone());
                        confirmTicketOrderYzDTO.setMobile(customer.getPhone());
                        confirmTicketOrderYzDTO.setCinemaLinkId(fs.getCinemaLinkId());
                        confirmTicketOrderYzDTO.setScheduleId(fs.getScheduleId());
                        confirmTicketOrderYzDTO.setScheduleKey(fs.getScheduleKey());
                        confirmTicketOrderYzDTO.setLockOrderId(order.getLockOrderId());
                        confirmTicketOrderYzDTO.setOutId(order.getOutId());
                        confirmTicketOrderYzDTO.setOrderAmount(order.getOrderAmount());
                        confirmTicketOrderYzDTO.setPayAmount(order.getPayAmount());
                        confirmTicketOrderYzDTO.setPromoAmount(order.getPromoAmount());

                        confirmTicketOrderYzDTO.setTicketList(order.getOrderTicketList());
                        confirmTicketOrderYzDTO.setPaymentList(order.getOrderPaymentList());
                        confirmTicketOrderYzDTO.setPromotionList(order.getOrderPromotionList());

                        YzResult<ConfirmTicketRetYzDTO> ret = YzUtils.confirmTicketOrder(confirmTicketOrderYzDTO,accessToken);
                        if(ret.getResultCode().equals(Constants.YZSUCCESS) && ret.getData().getBizCode().equals(Constants.BIZSUCCESS)){
                            order.setYzOrderId(ret.getData().getBizData().getOrderId());
                            order.setStatus(OrderConstant.ORDER_STATUS_CONFIRM_SUCCESS);
                            order.setUpdateTime(new Date(System.currentTimeMillis()));
                            orderMapper.updateOrder(order);
                            orderService.getOrderInfo(order,fs.getCinemaLinkId(),order.getYzOrderId(),accessToken,customer);
                            redisCache.deleteObject(order.getLockOrderId()+Constants.LOCK_SEAT_KEY);
                        }else {
                            order.setStatus(OrderConstant.ORDER_STATUS_CONFIRM_FAIL);
                            orderMapper.updateOrder(order);
                            orderService.getFailedOrderInfo(order);
                            redisCache.deleteObject(order.getLockOrderId()+Constants.LOCK_SEAT_KEY);
                            YzUtils.unlockSeat(fs.getCinemaLinkId(),order.getLockOrderId(),accessToken);
                        }
                    }
                    Map<String, String> xml = new HashMap<String, String>(2);
                    xml.put("return_code", "SUCCESS");
                    xml.put("return_msg", "OK");
                    return WxPayKit.toXml(xml);
                }else {
                    Map<String, String> xml = new HashMap<String, String>(2);
                    xml.put("return_code", "SUCCESS");
                    xml.put("return_msg", "OK");
                    return WxPayKit.toXml(xml);
                }
            }
        }
        return null;
    }

      @PostMapping("/testConfirmTicketOrder")
      public AjaxResult testConfirmTicketOrder(@RequestBody OrderBO orderBO){
          ConfirmTicketOrderYzDTO confirmTicketOrderYzDTO = new ConfirmTicketOrderYzDTO();
          Customer customer =  customerService.selectCustomerById(orderBO.getCustomerId());
          FilmSchedule fs = filmScheduleService.selectFilmScheduleById(orderBO.getScheduleId());
          String accessToken = customerService.getAccessToken(customer.getId(),customer.getPhone());
          confirmTicketOrderYzDTO.setMobile(customer.getPhone());
          confirmTicketOrderYzDTO.setCinemaLinkId(fs.getCinemaLinkId());
          confirmTicketOrderYzDTO.setScheduleId(fs.getScheduleId());
          confirmTicketOrderYzDTO.setScheduleKey(fs.getScheduleKey());
          confirmTicketOrderYzDTO.setLockOrderId(orderBO.getLockOrderId());
          confirmTicketOrderYzDTO.setOrderAmount(orderBO.getOrderAmount());
          confirmTicketOrderYzDTO.setPayAmount(orderBO.getPayAmount());
          confirmTicketOrderYzDTO.setPromoAmount(orderBO.getPromoAmount());
          List<OrderTicket> orderTicketList = new ArrayList<>(orderBO.getTicketList().size());
          for (OrderTicketBO otb:orderBO.getTicketList()) {
              OrderTicket ot = new OrderTicket();
              ot.setSeatCode(otb.getSeatCode());
              ot.setActivityCode(otb.getActivityCode());
              orderTicketList.add(ot);
          }
          confirmTicketOrderYzDTO.setTicketList(orderTicketList);
          confirmTicketOrderYzDTO.setPaymentList(orderBO.getOrderPaymentList());
          confirmTicketOrderYzDTO.setPromotionList(orderBO.getOrderPromotionList());

          YzResult<ConfirmTicketRetYzDTO> ret = YzUtils.confirmTicketOrder(confirmTicketOrderYzDTO,accessToken);
          return AjaxResult.success(ret);
      }

      @GetMapping("/getOrderInfo")
      public AjaxResult getOrderInfo(Order order){
          if(null == order.getId()){
              return AjaxResult.error(-1,"orderId必传");
          }
         OrderVO od =  orderMapper.selectOrderForApiById(order);
          return AjaxResult.success(od);
      }


      @GetMapping("/getOrderList")
      public TableDataInfo getOrderList(Order order){
        if(null == order.getCustomerId()){
            return getDataTableError(-1,"customerId 不能为空");
        }
        Customer customer = customerService.selectCustomerById(order.getCustomerId());
        if(null == customer){
            return getDataTableError(-1,"找不到对应的用户");
        }
        startPage();
        order.setType(OrderConstant.ORDER_TYPE_TICKET);
        return orderService.selectTicketOrderForApi(order);
      }

    @GetMapping("/getGoodsOrderInfo")
    public AjaxResult getGoodsOrderInfo(Order order){
        if(null == order.getId()){
            return AjaxResult.error(-1,"orderId必传");
        }
        OrderVO od =  orderMapper.selectOrderForApiById(order);
        return AjaxResult.success(od);
    }

    @GetMapping("/getGoodsOrderList")
    public TableDataInfo getGoodsOrderList(Order order){
        if(null == order.getCustomerId()){
            return getDataTableError(-1,"customerId 不能为空");
        }
        Customer customer = customerService.selectCustomerById(order.getCustomerId());
        if(null == customer){
            return getDataTableError(-1,"找不到对应的用户");
        }
        startPage();
        order.setType(OrderConstant.ORDER_TYPE_GOODS);
        return orderService.selectGoodsOrderForApi(order);


    }



      @PostMapping("/refundOrder")
      public AjaxResult refundOrder(@RequestBody OrderInfoBO orderInfoBO){
        if(null == orderInfoBO.getCustomerId()){
            return AjaxResult.error(-1,"customerId 不能为空");
        }
        if(null == orderInfoBO.getOrderId()){
            return AjaxResult.error(-1,"orderId 不能为空");
        }
        Order o = new Order();
        o.setId(orderInfoBO.getOrderId());
        List<Order> orderList = orderMapper.selectOrderAllList(o);
        if(null == orderList || orderList.isEmpty()){
            return AjaxResult.error(-1,"找不到对应的订单");
        }
        Order order = orderList.get(0);
        if(!order.getStatus().equals(OrderConstant.ORDER_STATUS_CONFIRM_FAIL) && !order.getStatus().equals(OrderConstant.ORDER_STATUS_CONFIRM_SUCCESS)){
            return AjaxResult.error(-1,"当前订单状态不支持退款");
        }

        Cinema cinema = cinemaService.selectCinemaById(order.getCinemaId());

          Customer customer = customerService.selectCustomerById(orderInfoBO.getCustomerId());
          if(null == customer){
              return AjaxResult.error(-1,"找不到对应的用户");
          }
          String accessToken = customerService.getAccessToken(customer.getId(),customer.getPhone());
        //todo 这里查order 的全部内容
        return orderService.refundOrder(order,accessToken, cinema.getCinemaLinkId(), IdUtils.fastSimpleUUID());

      }


    @PostMapping("/refundWechat")
    public AjaxResult refundWechat(@RequestBody OrderInfoBO orderInfoBO){
        if(null == orderInfoBO.getOrderId()){
            return AjaxResult.error(-1,"orderId 不能为空");
        }
        Order o = new Order();
        o.setId(orderInfoBO.getOrderId());
        List<Order> orderList = orderMapper.selectOrderAllList(o);
        if(null == orderList || orderList.isEmpty()){
            return AjaxResult.error(-1,"找不到对应的订单");
        }
        Order order = orderList.get(0);
        List<OrderPayment> orderPaymentList = order.getOrderPaymentList();
        String outTradeNo = null;
        Long payAmount = 0L;
        for (OrderPayment op :orderPaymentList) {
            if(op.getPayMethodCode().equals(OrderConstant.WEIXIN)){
                outTradeNo = op.getPayCode();
                payAmount += op.getPayAmount();
            }
        }
        OrderRefund orderRefund = new OrderRefund();
        orderRefund.setOutTradeNo(outTradeNo);
        orderRefund.setTotalAmount(payAmount);
        orderRefund.setWechatRefundAmount(payAmount);
        orderRefund.setRefundCode(IdUtils.fastSimpleUUID());
        boolean isRefund = orderService.wechatRefund(orderRefund);
        if(isRefund){
            return AjaxResult.success("退款成功");
        }else {
            return AjaxResult.error(-1,"退款失败");
        }
    }


    /**
     * 退款通知
     */
    @RequestMapping(value = "/wechatRefundNotify", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String wechatRefundNotify(HttpServletRequest request) {
        String xmlMsg = HttpKit.readData(request);
        logger.info("退款通知=" + xmlMsg);
        Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);

        String returnCode = params.get("return_code");
        // 注意重复通知的情况，同一订单号可能收到多次通知，请注意一定先判断订单状态
        if (WxPayKit.codeIsOk(returnCode)) {
            String reqInfo = params.get("req_info");
//            String decryptData = WxPayKit.decryptData(reqInfo, WechatConstants.WECHAT_KEY);
//            logger.info("退款通知解密后的数据=" + decryptData);

            // 更新订单信息
            // 发送通知等
            Map<String, String> xml = new HashMap<String, String>(2);
            xml.put("return_code", "SUCCESS");
            xml.put("return_msg", "OK");
            return WxPayKit.toXml(xml);
        }
        return null;
    }



      @PostMapping("/confirmCardOrder")
      public AjaxResult confirmCardOrder(@RequestBody Map<String,Object> parm){
        String ret = YzUtils.confirmCardOrder(parm);
        return AjaxResult.success(JSON.parseObject(ret));
      }



    @PostMapping("/rechargeCard")
    public AjaxResult rechargeCard(@RequestBody RechargeCardBO rechargeCardBO,HttpServletRequest request){
        if(null == rechargeCardBO.getCustomerId()){
            return AjaxResult.error(-1,"customerId 不能为空");
        }
        Customer customer = customerService.selectCustomerById(rechargeCardBO.getCustomerId());
        if(null == customer){
            return AjaxResult.error(-1,"找不到对应的用户");
        }
        String accessToken = customerService.getAccessToken(customer.getId(),customer.getPhone());
        YzResult<CardInfoYzDTO> cardInfoYzDTOYzResult = YzUtils.getCardInfo(accessToken,rechargeCardBO.getCardNo());
        if(!cardInfoYzDTOYzResult.getResultCode().equals(Constants.YZSUCCESS) || !cardInfoYzDTOYzResult.getData().getBizCode().equals(Constants.BIZSUCCESS)){
            return AjaxResult.error(-1,"找不到对应的卡号");
        }
        CardInfoYzDTO cardInfoYzDTO = cardInfoYzDTOYzResult.getData().getBizData();
        if(null == cardInfoYzDTO){
            return AjaxResult.error(-1,"找不对对应的卡号");
        }
        MemberCardOrder memberCardOrder = new MemberCardOrder();
        if(rechargeCardBO.getCardType().equals("BENEFIT")){
            return AjaxResult.error(-1,"权益卡暂时不能续费");
//            memberCardOrder.setMembershipFee(rechargeCardBO.getPayAmount());
//            memberCardOrder.setType(OrderConstant.MEMBER_ORDER_TYPE_BENEFIT_RECHARGE);
        }
        if(rechargeCardBO.getCardType().equals("DEPOSIT")){
            memberCardOrder.setType(OrderConstant.MEMBER_ORDER_TYPE_DEPOSIT_RECHARGE);
        }
        memberCardOrder.setStatus(OrderConstant.MEMBER_ORDER_STATUS_WAIT_PAY);
        memberCardOrder.setCardRuleId(cardInfoYzDTO.getCardRuleId());
        memberCardOrder.setCustomerId(customer.getId());
        memberCardOrder.setCardAmount(rechargeCardBO.getPayAmount());
        memberCardOrder.setOrderAmount(rechargeCardBO.getPayAmount());
        memberCardOrder.setPayAmount(rechargeCardBO.getPayAmount());
        memberCardOrder.setOutOrderId(IdUtils.fastSimpleUUID());
        memberCardOrder.setCardNo(rechargeCardBO.getCardNo());
        memberCardOrder.setPayCode(memberCardOrder.getOutOrderId());
        memberCardOrderService.insertMemberCardOrder(memberCardOrder);
        return orderService.wechatPrePay(memberCardOrder.getId(),
                memberCardOrder.getPayAmount(),
                customer.getOpenId(),
                memberCardOrder.getOutOrderId(),
                request,60L*60L,
                "中视电影会员卡充值",
                WechatConstants.WECHAT_MEMBER_ORDER_NOTIFY_URL);
    }



    @RequestMapping(value = "/memberOrderWechatNotify", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String memberOrderWechatNotify(HttpServletRequest request) {
        String xmlMsg = HttpKit.readData(request);
        logger.info("会员卡 支付通知=" + xmlMsg);
        Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);

        String returnCode = params.get("return_code");

        // 注意重复通知的情况，同一订单号可能收到多次通知，请注意一定先判断订单状态
        // 注意此处签名方式需与统一下单的签名类型一致
        if (WxPayKit.verifyNotify(params, WechatConstants.WECHAT_KEY, SignType.HMACSHA256)) {
            if (WxPayKit.codeIsOk(returnCode)) {
                // 更新订单信息
                // 发送通知等
                String out_trade_no = params.get("out_trade_no");
                MemberCardOrder o = new MemberCardOrder();
                o.setPayCode(out_trade_no);
                List<MemberCardOrder> orderList = memberCardOrderService.selectMemberCardOrderList(o);
                if(null == orderList || orderList.isEmpty()){
                    logger.error("------找不到订单--------");
                    return null;
                }
                if(orderList.size()> 1){
                    logger.error("-----找到了多个订单-------");
                }
                MemberCardOrder order = orderList.get(0);
                if(order.getStatus().equals(OrderConstant.MEMBER_ORDER_STATUS_WAIT_PAY)){
                    order.setStatus(OrderConstant.MEMBER_ORDER_STATUS_CONFIRM_FAIL);
                    int i =  memberCardOrderMapper.updateOptimisticLock(order);
                    if(i == 1) {
                        if (order.getType().equals(OrderConstant.MEMBER_ORDER_TYPE_DEPOSIT_RECHARGE)) {
                            ConfirmRechargeOrderYzDTO confirmRechargeOrderYzDTO = new ConfirmRechargeOrderYzDTO();
                            confirmRechargeOrderYzDTO.setOutId(order.getOutOrderId());
                            confirmRechargeOrderYzDTO.setCinemaLinkId("12971");
                            confirmRechargeOrderYzDTO.setOrderAmount(order.getOrderAmount());
                            confirmRechargeOrderYzDTO.setPayAmount(order.getPayAmount());
                            CardInfoYzDTO cardInfoYzDTO = new CardInfoYzDTO();
                            cardInfoYzDTO.setCardNo(order.getCardNo());
                            cardInfoYzDTO.setCardAmount(order.getCardAmount());
                            confirmRechargeOrderYzDTO.setCardInfoYzDTO(cardInfoYzDTO);
                            PaymentYzDTO paymentYzDTO = new PaymentYzDTO();
                            paymentYzDTO.setPayAmount(order.getPayAmount());
                            paymentYzDTO.setPayCode(order.getPayCode());
                            paymentYzDTO.setPayMethodCode(OrderConstant.WEIXIN);
                            List<PaymentYzDTO> paymentYzDTOList = new ArrayList<>(1);
                            paymentYzDTOList.add(paymentYzDTO);
                            confirmRechargeOrderYzDTO.setPaymentList(paymentYzDTOList);
                            Customer customer = customerService.selectCustomerById(order.getCustomerId());
                            String accessToken = customerService.getAccessToken(customer.getId(), customer.getPhone());
                            YzResult<ConfirmTicketRetYzDTO> ret = YzUtils.confirmRechargeOrder(confirmRechargeOrderYzDTO, accessToken);
                            if (ret.getResultCode().equals(Constants.YZSUCCESS) && ret.getData().getBizCode().equals(Constants.BIZSUCCESS)) {
                                order.setYzOrderId(ret.getData().getBizData().getOrderId());
                                order.setStatus(OrderConstant.MEMBER_ORDER_STATUS_CONFIRM_SUCCESS);
                                memberCardOrderService.updateMemberCardOrder(order);
                            }
                        }
                        if(order.getType().equals(OrderConstant.MEMBER_ORDER_TYPE_BENEFIT_RECHARGE)){
                            ConfirmExtensionFeeOrderYzDTO cfeyd = new ConfirmExtensionFeeOrderYzDTO();
                            cfeyd.setCardNo(order.getCardNo());
                            cfeyd.setCinemaLinkId("12971");
                            cfeyd.setMembershipFee(order.getMembershipFee());
                            cfeyd.setPayAmount(order.getPayAmount());
                            cfeyd.setOrderAmount(order.getOrderAmount());
                            cfeyd.setOutOrderId(order.getOutOrderId());
                            PaymentYzDTO paymentYzDTO = new PaymentYzDTO();
                            paymentYzDTO.setPayAmount(order.getPayAmount());
                            paymentYzDTO.setPayCode(order.getPayCode());
                            paymentYzDTO.setPayMethodCode(OrderConstant.WEIXIN);
                            List<PaymentYzDTO> paymentYzDTOList = new ArrayList<>(1);
                            paymentYzDTOList.add(paymentYzDTO);
                            cfeyd.setPaymentList(paymentYzDTOList);
                            Customer customer = customerService.selectCustomerById(order.getCustomerId());
                            String accessToken = customerService.getAccessToken(customer.getId(), customer.getPhone());
                            YzResult<ConfirmTicketRetYzDTO> ret = YzUtils.confirmExtensionFeeOrder(cfeyd, accessToken);
                            if (ret.getResultCode().equals(Constants.YZSUCCESS) && ret.getData().getBizCode().equals(Constants.BIZSUCCESS)) {
                                order.setYzOrderId(ret.getData().getBizData().getOrderId());
                                order.setStatus(OrderConstant.MEMBER_ORDER_STATUS_CONFIRM_SUCCESS);
                                memberCardOrderService.updateMemberCardOrder(order);
                            }
                        }
                    }
                    Map<String, String> xml = new HashMap<String, String>(2);
                    xml.put("return_code", "SUCCESS");
                    xml.put("return_msg", "OK");
                    return WxPayKit.toXml(xml);
                }else {
                    Map<String, String> xml = new HashMap<String, String>(2);
                    xml.put("return_code", "SUCCESS");
                    xml.put("return_msg", "OK");
                    return WxPayKit.toXml(xml);
                }


            }
        }
        return null;
    }


    @RepeatSubmit
    @PostMapping("/goodsOrderPrePay")
    public AjaxResult goodsOrderPrePay(@RequestBody GoodsOrderBO goodsOrderBO, HttpServletRequest request){
        if(null == goodsOrderBO.getCustomerId()){
            return AjaxResult.error(-1,"customerId 不能为空");
        }
        Customer customer = customerService.selectCustomerById(goodsOrderBO.getCustomerId());
        if(null == customer){
            return AjaxResult.error(-1,"找不到对应的用户");
        }
        if(null == goodsOrderBO.getCinemaId()){
            return AjaxResult.error(-1,"cinemaId不能为空");
        }
        Cinema cinema = cinemaService.selectCinemaById(goodsOrderBO.getCinemaId());
        if(null == cinema){
            return AjaxResult.error(-1,"找不到对应的影院");
        }
        goodsOrderBO.setCinemaLinkId(cinema.getCinemaLinkId());
        String accessToken = customerService.getAccessToken(customer.getId(),customer.getPhone());
        if(StringUtils.isEmpty(accessToken)){
            return AjaxResult.error(-1,"获取accessToken失败，请绑定手机号后重试");
        }
        customer.setAccessToken(accessToken);
        if(StringUtils.isEmpty(goodsOrderBO.getMobile())){
            goodsOrderBO.setMobile(customer.getPhone());
        }
        if(null == goodsOrderBO.getOrderGoodsList() || goodsOrderBO.getOrderGoodsList().isEmpty()){
            return AjaxResult.error(-1,"orderGoodsList不能为空");
        }

        Order order = new Order();
        order.setOrderAmount(goodsOrderBO.getOrderAmount());
        order.setPayAmount(goodsOrderBO.getPayAmount());
        order.setPromoAmount(goodsOrderBO.getPromoAmount());
        order.setMobile(goodsOrderBO.getMobile());
        order.setCinemaId(cinema.getId());
        order.setCustomerId(goodsOrderBO.getCustomerId());
        order.setOutId(IdUtils.fastSimpleUUID());
        order.setType(OrderConstant.ORDER_TYPE_GOODS);
        order.setStatus(OrderConstant.ORDER_STATUS_WAIT_PAY);
        order.setGoodsPayAmount(goodsOrderBO.getPayAmount());
        orderService.insertOrder(order);
        List<OrderGoods> orderGoodsList = new ArrayList<>();
        for (OrderGoods og :goodsOrderBO.getOrderGoodsList()) {
            OrderGoods orderGoods = new OrderGoods();
            orderGoods.setOrderId(order.getId());
            orderGoods.setGoodsCode(og.getGoodsCode());
            orderGoods.setGoodsCount(og.getGoodsCount());
            orderGoods.setCategoryCode(og.getCategoryCode());
            orderGoods.setActivityCode(og.getActivityCode());
            orderGoodsService.insertOrderGoods(orderGoods);
            if(null != og.getComboList() && !og.getComboList().isEmpty()){
                List<OrderGoodsCombo> comboList = new ArrayList<>();
                for (OrderGoodsCombo ogc :og.getComboList()) {
                    OrderGoodsCombo orderGoodsCombo = new OrderGoodsCombo();
                    orderGoodsCombo.setGoodsCode(ogc.getGoodsCode());
                    orderGoodsCombo.setGoodsCount(ogc.getGoodsCount());
                    orderGoodsCombo.setGoodsType(ogc.getGoodsType());
                    orderGoodsCombo.setGroupId(ogc.getGroupId());
                    orderGoodsCombo.setExtraMoney(ogc.getExtraMoney());
                    orderGoodsCombo.setOrderGoodsId(orderGoods.getId());
                    orderGoodsComboService.insertOrderGoodsCombo(orderGoodsCombo);
                    comboList.add(orderGoodsCombo);
                }
                orderGoods.setComboList(comboList);
            }
            orderGoodsList.add(orderGoods);
        }
        order.setOrderGoodsList(orderGoodsList);
        if(null != goodsOrderBO.getOrderPromotionList()){
            List<OrderPromotion> orderPromotionList = new ArrayList<>();
            for (OrderPromotion op :goodsOrderBO.getOrderPromotionList()) {
                OrderPromotion orderPromotion = new OrderPromotion();
                orderPromotion.setOrderId(order.getId());
                orderPromotion.setPromoAmount(op.getPromoAmount());
                orderPromotion.setPromoCode(op.getPromoCode());
                orderPromotion.setPromoType(op.getPromoType());
                orderPromotionService.insertOrderPromotion(orderPromotion);
                orderPromotionList.add(orderPromotion);
            }
            order.setOrderPromotionList(orderPromotionList);
        }
        OrderPayment oldOrderPayment = goodsOrderBO.getOrderPaymentList().get(0);

        List<OrderPayment> orderPaymentList = new ArrayList<>(2);

        OrderPayment orderPayment = new OrderPayment();
        orderPayment.setOrderId(order.getId());
        orderPayment.setPayAmount(oldOrderPayment.getPayAmount());
        if(oldOrderPayment.getPayMethodCode().equals(OrderConstant.WEIXIN)){
            orderPayment.setPayCode(IdUtils.fastSimpleUUID());
        }
        if(oldOrderPayment.getPayMethodCode().equals(OrderConstant.MEMBER_CARD)){
            orderPayment.setPayCode(oldOrderPayment.getPayCode());
        }
        orderPayment.setPayMethodCode(oldOrderPayment.getPayMethodCode());
        orderPaymentService.insertOrderPayment(orderPayment);
        orderPaymentList.add(orderPayment);

        OrderPayment couponOrderPay = null;
        OrderPayment couponPay = goodsOrderBO.getCouponPay();
        if(null != couponPay && null != couponPay.getPayAmount()){
            couponOrderPay = new OrderPayment();
            couponOrderPay.setOrderId(order.getId());
            couponOrderPay.setPayAmount(couponPay.getPayAmount());
            couponOrderPay.setPayMethodCode(couponPay.getPayMethodCode());
            couponOrderPay.setPayCode(couponPay.getPayCode());
            couponOrderPay.setPayApply("GOODS");
            orderPaymentService.insertOrderPayment(couponOrderPay);
            orderPaymentList.add(couponOrderPay);
        }
        order.setOrderPaymentList(orderPaymentList);
        OrderFulfillInfo orderFulfillInfo = goodsOrderBO.getOrderFulfillInfo();
        if(null != orderFulfillInfo && !StringUtils.isEmpty(orderFulfillInfo.getFulfillPlace()) && null != orderFulfillInfo.getFulfillTime()){
            orderFulfillInfo.setOrderId(order.getId());
            orderFulfillInfoService.insertOrderFulfillInfo(orderFulfillInfo);
            order.setOrderFulfillInfo(orderFulfillInfo);
        }

        if(orderPayment.getPayMethodCode().equals(OrderConstant.WEIXIN) && (orderPayment.getPayAmount() > 0) ){
            return orderService.wechatPrePay(order.getId(),orderPayment.getPayAmount(), customer.getOpenId(), orderPayment.getPayCode(),request,60*10L,"中视电影购票(卖品)",WechatConstants.GOODS_WECHAT_NOTIFY_URL);
        }else if(orderPayment.getPayMethodCode().equals(OrderConstant.MEMBER_CARD)){
            return orderService.goodsMemberPay(order,customer);
        }else if(couponOrderPay != null){
            return orderService.memberPay(order,customer);
        }else{
            return AjaxResult.error(-1,"不支持的支付方式");
        }


    }


    @RequestMapping(value = "/goodsWechatNotify", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String goodsWechatNotify(HttpServletRequest request) {
        String xmlMsg = HttpKit.readData(request);
        logger.info("卖品 支付通知=" + xmlMsg);
        Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);

        String returnCode = params.get("return_code");

        // 注意重复通知的情况，同一订单号可能收到多次通知，请注意一定先判断订单状态
        // 注意此处签名方式需与统一下单的签名类型一致
        if (WxPayKit.verifyNotify(params, WechatConstants.WECHAT_KEY, SignType.HMACSHA256)) {
            if (WxPayKit.codeIsOk(returnCode)) {
                // 更新订单信息
                // 发送通知等
                String out_trade_no = params.get("out_trade_no");
                List<OrderPayment> opl = orderPaymentService.selectByPayCode(out_trade_no);
                if(null == opl || opl.isEmpty()){
                    logger.error("------找不到对应的微信支付--------");
                    return null;
                }
                if(opl.size() > 1){
                    logger.info("-----找到多个code 对应的支付------");
                }
                Order o = new Order();
                o.setId(opl.get(0).getOrderId());
                List<Order> orderList = orderMapper.selectOrderAllList(o);
                if(null == orderList || orderList.isEmpty()){
                    logger.error("------找不到订单--------");
                    return null;
                }
                if(orderList.size()> 1){
                    logger.error("-----找到了多个订单-------");
                }
                Order order = orderList.get(0);
                if(order.getStatus().equals(OrderConstant.ORDER_STATUS_WAIT_PAY)){
                    order.setStatus(OrderConstant.ORDER_STATUS_PAY_SUCCESS);
                    int i =  orderMapper.updateOptimisticLock(order);
                    if(i == 1){
                        ConfirmGoodsOrderYzDTO confirmGoodsOrderYzDTO = new ConfirmGoodsOrderYzDTO();
                        Customer customer =  customerService.selectCustomerById(order.getCustomerId());
                        Cinema cinema = cinemaService.selectCinemaById(order.getCinemaId());
                        String accessToken = customerService.getAccessToken(customer.getId(),customer.getPhone());
                        confirmGoodsOrderYzDTO.setMobile(order.getMobile());
                        confirmGoodsOrderYzDTO.setOutId(order.getOutId());
                        confirmGoodsOrderYzDTO.setOrderAmount(order.getOrderAmount());
                        confirmGoodsOrderYzDTO.setPayAmount(order.getPayAmount());
                        confirmGoodsOrderYzDTO.setPromoAmount(order.getPromoAmount());
                        confirmGoodsOrderYzDTO.setCinemaLinkId(cinema.getCinemaLinkId());
                        confirmGoodsOrderYzDTO.setGoodsList(order.getOrderGoodsList());
                        confirmGoodsOrderYzDTO.setPaymentList(order.getOrderPaymentList());
                        confirmGoodsOrderYzDTO.setPromotionList(order.getOrderPromotionList());
                        confirmGoodsOrderYzDTO.setFulfillInfo(order.getOrderFulfillInfo());
                        YzResult<ConfirmTicketRetYzDTO> ret = YzUtils.confirmGoodsOrder(confirmGoodsOrderYzDTO,accessToken);
                        if(ret.getResultCode().equals(Constants.YZSUCCESS) && ret.getData().getBizCode().equals(Constants.BIZSUCCESS)){
                            order.setYzOrderId(ret.getData().getBizData().getOrderId());
                            order.setStatus(OrderConstant.ORDER_STATUS_CONFIRM_SUCCESS);
                            order.setUpdateTime(new Date(System.currentTimeMillis()));
                            orderMapper.updateOrder(order);
                            orderService.getOrderInfo(order,cinema.getCinemaLinkId(),order.getYzOrderId(),accessToken,customer);
                        }else {
                            order.setStatus(OrderConstant.ORDER_STATUS_CONFIRM_FAIL);
                            orderMapper.updateOrder(order);
                            orderService.getFailedOrderInfo(order);
                        }
                    }
                    Map<String, String> xml = new HashMap<String, String>(2);
                    xml.put("return_code", "SUCCESS");
                    xml.put("return_msg", "OK");
                    return WxPayKit.toXml(xml);
                }else {
                    Map<String, String> xml = new HashMap<String, String>(2);
                    xml.put("return_code", "SUCCESS");
                    xml.put("return_msg", "OK");
                    return WxPayKit.toXml(xml);
                }
            }
        }
        return null;
    }

    @GetMapping("/testSendMessage")
    public AjaxResult testSendMessage(Order order){
        if(null == order.getId()){
            return AjaxResult.error(-1,"orderId必传");
        }
        List<Order> orderList  =  orderMapper.selectOrderAllList(order);
        Order od = orderList.get(0);
        Customer customer = customerService.selectCustomerById(od.getCustomerId());
        Cinema c = cinemaService.selectCinemaById(od.getCinemaId());
        OrderFulfillInfo info = orderFulfillInfoService.selectOrderFulfillInfoById(od.getOrderFulfillInfo().getId());
        od.setOrderFulfillInfo(info);
        GoodsBuyedMsgBo goodsBuyedMsgBo = new GoodsBuyedMsgBo(od,customer,c.getCinemaLinkId());
        GoodsBuyEvent goodsBuyEvent = new GoodsBuyEvent(goodsBuyedMsgBo);
        applicationContext.publishEvent(goodsBuyEvent);

        return AjaxResult.success(od);
    }

}
